﻿(*                  FnSharp              

   Base class library extensions and frameworks aimed 
   specifically at improving F# developers lives!

   Written by: Huw Simpson
   License: Microsoft Public License (Ms-PL) 
   Available at: http://fnsharp.codeplex.com

*)
namespace FnSharp.Bcl.Core

    open System
    open System.Collections.Generic

    [<RequireQualifiedAccess>]
    [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
    module List =
        /// Group the items in a list by a supplied function which returns the desired grouping action.
        [<CompiledName("GroupBy2")>]
        let groupBy2 f (source:'t list) = [
            let group = new List<'t> ()
            let drain () = group.Count > 0 |> Option.ofBoolF2 (group.ToArray >> Array.toList) (ignore >> group.Clear)

            for e in source do
                match f e (group.ToArray ()) with
                | YieldGroup itemAction ->
                    match drain (), itemAction with
                    | None,     GroupItem    -> group.Add e
                    | Some g,   GroupItem    -> group.Add e; yield g
                    | None,     AppendItem   -> yield [e]
                    | Some g,   AppendItem   -> yield [e] |> List.append g
                    | None,     DiscardItem  -> ()
                    | Some g,   DiscardItem  -> yield g
                    | None,     SeperateItem -> yield [e]
                    | Some g,   SeperateItem -> yield g; yield [e]
                | ContinueGroup itemAction ->
                    match itemAction with
                    | WithItem -> group.Add e
                    | WithoutItem -> () 

            match drain () with 
            | None -> ()
            | Some g -> yield g ]          
            
        /// Group the items in a list by a supplied function which returns the desired grouping action.
        [<CompiledName("GroupBy")>]
        let inline groupBy f source =
            let fx a b = f a
            source |> groupBy2 fx  
